#!/usr/bin/env bash

# FOLLOWING SERVICES RUN INSIDE A SINGLE DOCKER CONTAINER
# - PROXY
# - XSWITCH (1..*)
# - RECORDING CONTROLLER
# - RECORDING WORKER (1..*)

# GENERAL CONFIGS
# IMAGE_NAME="docker-registry.easemob.com/kefu/rtc-xswitch"
# IMAGE_VERSION="2.1.2"
# HOME="/data/apps/rtc"

mkdir -p /data/recorder
rm -f /data/recorder/log
ln -s /data/logs /data/recorder/log


function fail2die {
    "$@"
    local status=$?
    if [ $status -ne 0 ]; then
        echo "failed: $@" >&2
        exit 1
    fi
}

function exit_if_ne() {
    local actual=$1
    local expect=$2
    local what=$3
    if [[ ${actual} -ne ${expect} ]]; then
        echo "$what failed, exiting" >&2
        exit -1
    fi
}

function get_eth_address() {
    local eth_name=$1
    ifconfig ${eth_name} 2>/dev/null | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
}

if [ -z "$XSWITCH_INTERNAL_IP" ]; then
    INTERNAL_IP=$(get_eth_address "eth0")
else
    INTERNAL_IP=${XSWITCH_INTERNAL_IP}
fi
echo "xswitch internal ip: $INTERNAL_IP"

if [ -z "$XSWITCH_EXTERNAL_IP" ]; then
    EXTERNAL_IP=$(get_eth_address "eth1")
else
    EXTERNAL_IP=${XSWITCH_EXTERNAL_IP}
fi
if [ -z "$EXTERNAL_IP" ]; then
    EXTERNAL_IP=$INTERNAL_IP
fi

# [ -z "$XSWITCH_EXTERNAL_IP2" ] && XSWITCH_EXTERNAL_IP2=$(curl -s --connect-timeout 3 http://100.100.100.200/latest/meta-data/eipv4)
# [ -z "$XSWITCH_EXTERNAL_IP2" ] && XSWITCH_EXTERNAL_IP2=$(curl -s --connect-timeout 10 ip.sb)
echo "xswitch external ip: $EXTERNAL_IP-->${XSWITCH_EXTERNAL_IP2:-"$EXTERNAL_IP"}"

ERROR=0
function warn_if_ne() {
    local actual=$1
    local expect=$2
    local what=$3
    if [[ ${actual} -ne ${expect} ]]; then
        echo "$what failed" >&2
        ERROR=-1
    fi
}

# PROXY CONFIGS
PROXY_HTTP_HOST="${INTERNAL_IP}"
PROXY_HTTP_PORT="${XSWITCH_PROXY_HTTP_PORT:-$PORT0}"
PROXY_HTTP_ADDR="${PROXY_HTTP_HOST}:${PROXY_HTTP_PORT}"
PROXY_WS_ADDR="${INTERNAL_IP}:${XSWITCH_PROXY_WEBSOCKET_PORT:-$PORT1}"

PROXY_CMD_OPT=(
    -api=${PROXY_HTTP_ADDR}
    -backend=${PROXY_WS_ADDR}
    -log-level=*=DEBUG
    -job-dir=/data/recorder/job/
    -log-dir=/data/logs
)

serviceId=${APP_NAME:-xswitch}-${PROXY_HTTP_HOST}-${PROXY_HTTP_PORT}-${RANDOM}
PROXY_REGISTER_PAYLOAD=$(cat <<-EOF
{
  "ID":      "$serviceId",
  "Name":    "${APP_NAME:-xswitch}",
  "Tags":    ["version=${IMAGE_VERSION:-$PKG_VERSION}", "http_port=${PROXY_HTTP_PORT}"],
  "Address": "${PROXY_HTTP_HOST}",
  "Port":    ${PROXY_HTTP_PORT},
  "Check":   {
    "Name":      "xswitch status check",
    "Notes":     "checks whether the /status uri is responsive",
    "HTTP":      "http://${PROXY_HTTP_ADDR}/status",
    "Interval":  "${CONSUL_CHECK_INTERVAL:-10s}",
    "DeregisterCriticalServiceAfter": "${CONSUL_DEREGISTER_CRITICAL_SERVICE_AFTER:-1m}"
  }
}
EOF
)

CONSUL_URL=${XSWITCH_CONSUL_URL:-http://localhost:8500} #"http://127.0.0.1:8500"

function register_proxy() {
    if [ -z "$CONSUL_URL" ]; then
        echo "XSWITCH_CONSUL_URL is empty. not register proxy to consul"
    else
        echo ${PROXY_REGISTER_PAYLOAD}
        local status=$(curl --request PUT ${CONSUL_URL}/v1/agent/service/register \
            --data "${PROXY_REGISTER_PAYLOAD}" \
            --silent --output /dev/stderr --write-out "%{http_code}")
        exit_if_ne ${status} 200 "register proxy"
    fi
}

function deregister_proxy() {
    if [ -z "$CONSUL_URL" ]; then
        echo "XSWITCH_CONSUL_URL is empty. not deregister proxy to consul"
    else
        local status=$(curl --request PUT \
            ${CONSUL_URL}/v1/agent/service/deregister/$serviceId \
            --data "${PROXY_REGISTER_PAYLOAD}" \
            --silent --output /dev/stderr --write-out "%{http_code}")
        warn_if_ne ${status} 200 "de-register proxy"
    fi
}

CHILD_PIDS=()

function start_proxy() {
    CMD=(proxy ${PROXY_CMD_OPT[@]})
    echo ${CMD[@]}
    ${CMD[@]} &
    CHILD_PIDS+=($!)
    register_proxy
}

# XSWITCH CONFIGS
XSWITCH_INSTANCES=${XSWITCH_INSTANCES:-2}
XSWITCH_HTTP_PORT_START=${XSWITCH_HTTP_PORT_START:-3018}
XSWITCH_UDP_PORT_START=${XSWITCH_UDP_PORT_START:-30000}
XSWITCH_UDP_PORT_COUNT_PER_INSTANCE=${XSWITCH_UDP_PORT_COUNT_PER_INSTANCE:-1000}

# udp port复用
XSWITCH_UDP_PORT_MUX=${XSWITCH_UDP_PORT_MUX:-"no"}

XSWITCH_CMD_OPT=(
    --record-path=/data/recorder/
    --http-ip=${INTERNAL_IP}
    --media-ip=${EXTERNAL_IP}
    --ipm-ip=127.0.0.1
    --proxy-addr=${PROXY_WS_ADDR}
    --max-video-bitrate=${MAX_VIDEO_BITRATE:-1000}
    --min-video-bitrate=${MIN_VIDEO_BITRATE:-50}
    --enable-fec
    --experiment-esmb
    --lost-0
    --translate-fec
)

if [ "${XSWITCH_EXTERNAL_IP2}" ]; then
  XSWITCH_CMD_OPT=(
    ${XSWITCH_CMD_OPT[@]}
    --media-ip2=${XSWITCH_EXTERNAL_IP2}
  )
fi

function start_mux_xswitches() { # 一个proxy 于 一个xswitch 对应，否则，ssrc有重复的危险
    XSWITCH_UDP_PORT_MIN=${XSWITCH_UDP_PORT_MIN:-40000}
    XSWITCH_UDP_PORT_MAX=${XSWITCH_UDP_PORT_MAX:-40000}

    i=0
    for udp_port in $(seq $XSWITCH_UDP_PORT_MIN $XSWITCH_UDP_PORT_MAX); do
      http_port=$(expr $XSWITCH_HTTP_PORT_START + $i)
      cp /app/conf/log4cplus.properties /app/conf/log4cplus.properties.${i}
      sed -i "s|/data/logs/rtc-xswitch.log|/data/logs/rtc-xswitch-${http_port}.log|" /app/conf/log4cplus.properties.${i}
      echo "xswitch $i: http-port=$http_port media-port=$udp_port-$udp_port"

      CMD=(rtc-xswitch ${XSWITCH_CMD_OPT[@]}
          --log-config=/app/conf/log4cplus.properties.${i}
          --http-port ${http_port}
          --min-port ${udp_port}
          --max-port ${udp_port}
          --nice-mux
      )
      echo ${CMD[@]}
      i=$(expr $i + 1)

      ${CMD[@]} 2>>/data/logs/rtc-xswitch.err &

      CHILD_PIDS+=($!)
    done
}

function start_xswitches() {
    for i in $(seq 1 $XSWITCH_INSTANCES); do
        http_port=$(expr $XSWITCH_HTTP_PORT_START + $i - 1)
        min_port=$(expr $XSWITCH_UDP_PORT_START + \( $i - 1 \) \* $XSWITCH_UDP_PORT_COUNT_PER_INSTANCE)
        max_port=$(expr $XSWITCH_UDP_PORT_START + $i \* $XSWITCH_UDP_PORT_COUNT_PER_INSTANCE - 1)
        cp /app/conf/log4cplus.properties /app/conf/log4cplus.properties.${i}
        sed -i "s|/data/logs/rtc-xswitch.log|/data/logs/rtc-xswitch-${http_port}.log|" /app/conf/log4cplus.properties.${i}
        echo "xswitch $i: http-port=$http_port media-port=$min_port-$max_port"

        CMD=(rtc-xswitch ${XSWITCH_CMD_OPT[@]}
            --log-config=/app/conf/log4cplus.properties.${i}
            --http-port ${http_port}
            --min-port ${min_port}
            --max-port ${max_port}
        )
        echo ${CMD[@]}
        ${CMD[@]} 2>>/data/logs/rtc-xswitch.err &

        CHILD_PIDS+=($!)
    done
}

# RECORDER CONTROLLER
RECORDER_CONTROLLER_HTTP_ADDR="${INTERNAL_IP}:${RECORDER_CTRL_HTTP_PORT:-$PORT2}"
RECORDER_CONTROLLER_CMD_OPT=(
    -listen=${RECORDER_CONTROLLER_HTTP_ADDR}
    -home="/data/recorder/"
    -keep=${RECORDER_KEEP_DAYS:-10}
    -id="recording-controller"
    -out-dir=${XSWITCH_RECORDS_OUT:-/data/recorder/out}
)

function start_recording_controller() {
    CMD=(recorder ${RECORDER_CONTROLLER_CMD_OPT[@]})
    echo ${CMD[@]}
    ${CMD[@]} &
    CHILD_PIDS+=$!
}

# RECORDER WORKER
RECORDER_WORKER_INSTANCES=${RECORDER_WORKER_INSTANCES:-4}
RECORDER_WORKER_CMD_OPT=(
    -connect=${RECORDER_CONTROLLER_HTTP_ADDR}
    -home="/data/recorder/"
    -keep=${RECORDER_KEEP_DAYS:-10}
    -notMergeWhenOneFile=${RECORDER_NOT_MERGE_WHEN_ONEFILE:-true}
    -out-dir=${XSWITCH_RECORDS_OUT:-/data/recorder/out}
)

function start_recording_workers() {
    for i in $(seq 1 ${RECORDER_WORKER_INSTANCES}); do
        CMD=(recorder ${RECORDER_WORKER_CMD_OPT[@]} -id="recording-worker-$i")
        echo ${CMD[@]}
        ${CMD[@]} &
        CHILD_PIDS+=($!)
    done
}

function start_proxy_xswitch() {
    start_proxy

    if [ "${XSWITCH_UDP_PORT_MUX}" = "yes" ]; then
        # nice mux
        start_mux_xswitches
    else
        start_xswitches
    fi
}

function start_records() {
    start_recording_controller
    start_recording_workers
}

function start_all() {
    start_proxy_xswitch
    start_records
}

function stop_child() {
    for pid in ${CHILD_PIDS[@]}; do
        kill $@ ${pid}
    done
}

function stop_all() {
    deregister_proxy
    stop_child
}

case $1 in
  xswitch)
    start_proxy_xswitch
    trap stop_all exit INT TERM
    ;;
  recorder)
    start_records
    trap stop_child exit INT TERM
    ;;
  *)
    start_all
    trap stop_all exit INT TERM
    ;;
esac

wait